package com.kexio.user.controller;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.kexio.auth.annotation.RateLimit;
import com.kexio.auth.annotation.RequiresPermission;
import com.kexio.auth.dto.UserAuthInfo;
import com.kexio.auth.util.AuthContextUtils;
import com.kexio.common.dto.PageResponse;
import com.kexio.common.dto.Result;
import com.kexio.common.page.PageConverters;
import com.kexio.common.page.PageUtils;
import com.kexio.user.dto.UserDTO;
import com.kexio.user.dto.UserStatistics;
import com.kexio.user.entity.User;
import com.kexio.user.service.RoleService;
import com.kexio.user.service.UserService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;

/**
 * 用户管理控制器
 * 
 * 提供用户管理相关的REST API，包括：
 * - 用户的增删改查
 * - 用户分页查询
 * - 用户状态管理
 * - 用户密码重置
 * - 用户角色分配
 * - 用户数据导入导出
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@RestController
@RequestMapping("/users")
@Tag(name = "用户管理", description = "用户管理相关API")
public class UserController {
    
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private RoleService roleService;
    
    @Autowired
    private com.kexio.user.mapper.UserMapper userMapper;
    
    // ==================== 用户CRUD API ====================
    
    /**
     * 创建用户
     */
    @PostMapping
    @RequiresPermission("user:create")
    @RateLimit(count = 20, time = 1)
    @Operation(summary = "创建用户", description = "创建新用户账户")
    public Result<UserDTO> createUser(
            @Valid @RequestBody UserDTO request) {
        
        logger.info("创建用户请求: username={}, tenantId={}", 
            request.getUsername(), request.getTenantId());
        
        // 验证请求参数
        request.validate();
        
        // 创建用户
        User user = userService.createUser(request);
        
        // 转换为响应DTO
        UserDTO userResponse = UserDTO.fromEntity(user);
        
        logger.info("创建用户成功: userId={}, username={}", 
            user.getId(), user.getUsername());
        
        return Result.success("用户创建成功", userResponse);
    }
    
    /**
     * 更新用户信息
     */
    @PutMapping("/{userId}")
    @RequiresPermission("user:update")
    @RateLimit(count = 30, time = 1)
    @Operation(summary = "更新用户信息", description = "更新指定用户的信息")
    public Result<UserDTO> updateUser(
            @Parameter(description = "用户ID") @PathVariable String userId,
            @Valid @RequestBody UserDTO request) {
        
        logger.info("更新用户请求: userId={}, tenantId={}", 
            userId, AuthContextUtils.getCurrentTenantId());
        
        // 验证并清理请求数据
        request.validate();
        
        if (!request.hasAnyUpdateFields()) {
            logger.warn("更新用户请求无任何更新内容: userId={}", userId);
            return Result.error("请提供要更新的内容");
        }
        
        // 更新用户
        User user = userService.updateUser(userId, request);
        
        // 转换为响应DTO
        UserDTO userResponse = UserDTO.fromEntity(user);
        
        logger.info("更新用户成功: userId={}, username={}", 
            user.getId(), user.getUsername());
        
        return Result.success("用户更新成功", userResponse);
    }
    
    /**
     * 获取用户详情
     */
    @GetMapping("/{userId}")
    @RequiresPermission("user:query")
    @Operation(summary = "获取用户详情", description = "获取指定用户的详细信息")
    public Result<UserDTO> getUser(
            @Parameter(description = "用户ID") @PathVariable String userId) {
        
        logger.debug("获取用户详情请求: userId={}", userId);
        
        User user = userService.getUserById(userId);
        
        if (user == null) {
            logger.warn("用户不存在: userId={}", userId);
            return Result.error("用户不存在");
        }
        
        // 转换为响应DTO
        UserDTO userResponse = UserDTO.fromEntity(user);
        
        logger.debug("获取用户详情成功: userId={}, username={}", 
            user.getId(), user.getUsername());
        
        return Result.success("获取成功", userResponse);
    }
    
    /**
     * 删除用户（软删除）
     */
    @DeleteMapping("/{userId}")
    @RequiresPermission("user:delete")
    @RateLimit(count = 10, time = 1)
    @Operation(summary = "删除用户", description = "软删除指定用户（逻辑删除）")
    public Result<Void> deleteUser(
            @Parameter(description = "用户ID") @PathVariable String userId) {
        
        logger.info("删除用户请求: userId={}, tenantId={}", 
            userId, AuthContextUtils.getCurrentTenantId());
        
        // 检查是否为当前用户
        UserAuthInfo currentUser = AuthContextUtils.getCurrentUser();
        if (currentUser != null && userId.equals(currentUser.getUserId())) {
            logger.warn("用户尝试删除自己: userId={}", userId);
            return Result.error("不能删除自己的账户");
        }
        
        // 删除用户
        boolean deleted = userService.deleteUser(userId);
        
        if (!deleted) {
            logger.warn("用户删除失败，可能用户不存在: userId={}", userId);
            return Result.error("用户不存在或已被删除");
        }
        
        logger.info("用户删除成功: userId={}", userId);
        
        return Result.<Void>success("用户删除成功", null);
    }
    
    // ==================== 用户查询API ====================
    
    /**
     * 分页查询用户列表
     */
    @GetMapping
    @RequiresPermission("user:query")
    @Operation(summary = "分页查询用户", description = "根据条件分页查询用户列表")
    public Result<PageResponse<UserDTO>> queryUsers(
            @Parameter(description = "查询条件（含分页参数）") UserDTO queryRequest) {
        
        logger.debug("分页查询用户请求: current={}, size={}, tenantId={}", 
            queryRequest.getCurrent(), 
            queryRequest.getSize(), 
            AuthContextUtils.getCurrentTenantId());
        
        // 规范分页参数（UserDTO已继承PageQuery）
        queryRequest.setCurrent(PageUtils.normalizePageNo(queryRequest.getCurrent()));
        queryRequest.setSize(PageUtils.normalizePageSize(queryRequest.getSize()));
        
        // 查询用户分页数据
        PageResponse<User> userPage = userService.queryUsers(queryRequest);
        
        // 转换为响应DTO并封装分页
        PageResponse<UserDTO> response = PageConverters.map(
            userPage.getRecords(),
            userPage.getTotal(),
            userPage.getCurrent(),
            userPage.getSize(),
            UserDTO::fromEntity
        );
        
        // 优化：通过MyBatis collection标签一次性查询用户和角色
        // ✓ 保留内部 catch：角色查询失败不影响主数据返回
        if (response.getData() != null && !response.getData().isEmpty()) {
            try {
                List<String> userIds = response.getData().stream()
                    .map(UserDTO::getUserId)
                    .collect(Collectors.toList());
                
                // 一条SQL搞定，直接返回User with List<Role>
                List<User> usersWithRoles = userMapper.selectUsersWithRoles(userIds);
                java.util.Map<String, User> userMap = usersWithRoles.stream()
                    .collect(Collectors.toMap(User::getId, u -> u));
                
                // 直接从User对象的roles字段填充到UserDTO
                response.getData().forEach(userDTO -> {
                    User user = userMap.get(userDTO.getUserId());
                    if (user != null && user.getRoles() != null) {
                        List<com.kexio.auth.dto.RoleInfo> roleInfos = user.getRoles().stream()
                            .map(role -> {
                                com.kexio.auth.dto.RoleInfo roleInfo = new com.kexio.auth.dto.RoleInfo();
                                roleInfo.setRoleId(role.getId());
                                roleInfo.setRoleCode(role.getCode());
                                roleInfo.setRoleName(role.getName());
                                return roleInfo;
                            })
                            .collect(Collectors.toList());
                        userDTO.setRoles(roleInfos);
                    }
                });
            } catch (Exception e) {
                logger.warn("批量获取用户角色失败: error={}", e.getMessage());
            }
        }
        
        logger.debug("分页查询用户成功: total={}, current={}, size={}", 
            userPage.getTotal(), userPage.getCurrent(), userPage.getSize());
        
        return Result.success("查询成功", response);
    }
    
    // ==================== 用户状态管理API ====================
    
    /**
     * 启用用户
     */
    @PutMapping("/{userId}/enable")
    @RequiresPermission("user:update")
    @RateLimit(count = 30, time = 1)
    @Operation(summary = "启用用户", description = "启用指定用户账户")
    public Result<Void> enableUser(
            @Parameter(description = "用户ID") @PathVariable String userId) {
        
        logger.info("启用用户请求: userId={}", userId);
        
        boolean enabled = userService.updateUserStatus(userId, 1);
        
        if (!enabled) {
            logger.warn("启用用户失败，用户不存在: userId={}", userId);
            return Result.error("用户不存在");
        }
        
        logger.info("用户启用成功: userId={}", userId);
        
        return Result.<Void>success("用户启用成功", null);
    }
    
    /**
     * 禁用用户
     */
    @PutMapping("/{userId}/disable")
    @RequiresPermission("user:update")
    @RateLimit(count = 30, time = 1)
    @Operation(summary = "禁用用户", description = "禁用指定用户账户")
    public Result<Void> disableUser(
            @Parameter(description = "用户ID") @PathVariable String userId) {
        
        logger.info("禁用用户请求: userId={}", userId);
        
        // 检查是否为当前用户
        UserAuthInfo currentUser = AuthContextUtils.getCurrentUser();
        if (currentUser != null && userId.equals(currentUser.getUserId())) {
            logger.warn("用户尝试禁用自己: userId={}", userId);
            return Result.error("不能禁用自己的账户");
        }
        
        boolean disabled = userService.updateUserStatus(userId, 0);
        
        if (!disabled) {
            logger.warn("禁用用户失败，用户不存在: userId={}", userId);
            return Result.error("用户不存在");
        }
        
        logger.info("用户禁用成功: userId={}", userId);
        
        return Result.<Void>success("用户禁用成功", null);
    }
    
    /**
     * 解锁用户
     */
    @PutMapping("/{userId}/unlock")
    @RequiresPermission("user:update")
    @RateLimit(count = 30, time = 1)
    @Operation(summary = "解锁用户", description = "解锁被锁定的用户账户")
    public Result<Void> unlockUser(
            @Parameter(description = "用户ID") @PathVariable String userId) {
        
        logger.info("解锁用户请求: userId={}", userId);
        
        boolean unlocked = userService.unlockUser(userId);
        
        if (!unlocked) {
            logger.warn("解锁用户失败，用户不存在或未锁定: userId={}", userId);
            return Result.error("用户不存在或未锁定");
        }
        
        logger.info("用户解锁成功: userId={}", userId);
        
        return Result.<Void>success("用户解锁成功", null);
    }
    
    // ==================== 密码管理API ====================
    
    /**
     * 重置用户密码
     */
    @PutMapping("/{userId}/reset-password")
    @RequiresPermission("user:reset-password")
    @RateLimit(count = 10, time = 1)
    @Operation(summary = "重置用户密码", description = "重置指定用户的密码为默认密码")
    public Result<String> resetUserPassword(
            @Parameter(description = "用户ID") @PathVariable String userId) {
        
        logger.info("重置用户密码请求: userId={}", userId);
        
        userService.resetUserPassword(userId);
        // 安全：不返回明文密码
        logger.info("重置用户密码成功: userId={}", userId);
        return Result.success("密码重置成功");
    }
    
    // ==================== 数据导出API ====================
    
    /**
     * 导出用户数据（使用Excel注解）
     */
    @GetMapping("/export")
    @RequiresPermission("user:export")
    @RateLimit(count = 10, time = 1)
    @Operation(summary = "导出用户数据", description = "使用@ExcelField注解导出用户数据到Excel文件")
    public void exportUsers(
            @Parameter(description = "查询条件") UserDTO queryRequest,
            HttpServletResponse response) {
        
        logger.info("导出用户数据请求: tenantId={}", AuthContextUtils.getCurrentTenantId());
        
        // 设置租户ID
        String tenantId = AuthContextUtils.getCurrentTenantId();
        queryRequest.setTenantId(tenantId);
        
        // 导出数据
        userService.exportUsers(queryRequest, response);
        
        logger.info("导出用户数据成功");
    }
    
    /**
     * 导入用户数据（使用Excel注解）
     */
    @PostMapping("/import")
    @RequiresPermission("user:import")
    @RateLimit(count = 5, time = 1)
    @Operation(summary = "导入用户数据", description = "使用@ExcelField注解从Excel文件导入用户数据")
    public Result<Map<String, Object>> importUsers(
            @Parameter(description = "Excel文件") @RequestParam("file") org.springframework.web.multipart.MultipartFile file,
            @Parameter(description = "是否更新已存在数据") @RequestParam(value = "updateSupport", defaultValue = "false") Boolean updateSupport) {
        
        logger.info("导入用户数据请求: filename={}, updateSupport={}", file.getOriginalFilename(), updateSupport);
        
        Map<String, Object> result = userService.importUsers(file, updateSupport);
        
        logger.info("导入用户数据完成: {}", result);
        
        return Result.success("导入完成", result);
    }
    
    /**
     * 下载用户导入模板
     */
    @GetMapping("/export/template")
    @RequiresPermission("user:export")
    @RateLimit(count = 20, time = 1)
    @Operation(summary = "下载导入模板", description = "下载用户Excel导入模板")
    public void downloadTemplate(HttpServletResponse response) {
        logger.info("下载用户导入模板");
        userService.downloadImportTemplate(response);
    }
    
    // ==================== 统计API ====================
    
    /**
     * 测试接口是否加载 (无权限要求)
     */
    @GetMapping("/debug/test-endpoint")
    @Operation(summary = "测试接口加载", description = "验证新接口是否被正确加载")
    public Result<String> testEndpoint() {
        UserAuthInfo userInfo = AuthContextUtils.getCurrentUser();
        String roles = userInfo != null && userInfo.getRoles() != null ? 
            userInfo.getRoles().stream()
                .map(role -> role.getRoleCode())
                .reduce("", (a, b) -> a + "," + b) : "none";
        return Result.success("接口加载成功！用户: " + AuthContextUtils.getCurrentUsername() + ", 角色: " + roles);
    }

    /**
     * 测试超级管理员跳过功能 (临时测试接口)
     */
    @GetMapping("/debug/test-super-admin")
    @RequiresPermission(value = "system:test:super", ignoreSuperAdmin = true)
    @Operation(summary = "测试超级管理员跳过", description = "测试@RequiresPermission的ignoreSuperAdmin功能")
    public Result<String> testSuperAdminSkip() {
        return Result.success("超级管理员跳过功能测试成功！当前用户: " + AuthContextUtils.getCurrentUsername());
    }

    /**
     * 获取用户统计信息
     */
    @GetMapping("/statistics")
    @RequiresPermission("user:query")
    @Operation(summary = "获取用户统计", description = "获取用户各种状态的统计信息")
    public Result<UserStatistics> getUserStatistics() {
        
        logger.debug("获取用户统计请求: tenantId={}", AuthContextUtils.getCurrentTenantId());
        
        UserStatistics statistics = userService.getUserStatistics();
        
        logger.debug("获取用户统计成功: total={}, active={}", 
            statistics.getTotalUsers(), statistics.getActiveUsers());
        
        return Result.success("获取成功", statistics);
    }
    
    /**
     * 批量删除用户
     */
    @DeleteMapping("/batch")
    @RequiresPermission("user:delete")
    @RateLimit(count = 5, time = 1)
    @Operation(summary = "批量删除用户", description = "批量删除多个用户（软删除）")
    public Result<String> batchDeleteUsers(
        @RequestBody @Valid @Parameter(description = "用户ID列表") List<String> userIds
    ) {
        
        logger.debug("批量删除用户请求: userIds={}, operator={}", 
            userIds, AuthContextUtils.getCurrentUserId());
        
        if (userIds == null || userIds.isEmpty()) {
            return Result.error("用户ID列表不能为空");
        }
        
        if (userIds.size() > 100) {
            return Result.error("一次最多只能删除100个用户");
        }
        
        String currentUserId = AuthContextUtils.getCurrentUserId();
        
        // 检查是否包含当前用户
        if (userIds.contains(currentUserId)) {
            return Result.error("不能删除当前登录用户");
        }
        
        int deleted = userService.batchDeleteUsers(userIds);
        
        logger.info("批量删除用户成功: count={}, operator={}", deleted, currentUserId);
        
        return Result.success(String.format("成功删除%d个用户", deleted));
    }
    
    /**
     * 批量启用用户
     */
    @PutMapping("/batch/enable")
    @RequiresPermission("user:update")
    @RateLimit(count = 10, time = 1)
    @Operation(summary = "批量启用用户", description = "批量启用多个用户账号")
    public Result<String> batchEnableUsers(
        @RequestBody @Valid @Parameter(description = "用户ID列表") List<String> userIds
    ) {
        
        logger.debug("批量启用用户请求: userIds={}, operator={}", 
            userIds, AuthContextUtils.getCurrentUserId());
        
        if (userIds == null || userIds.isEmpty()) {
            return Result.error("用户ID列表不能为空");
        }
        
        if (userIds.size() > 100) {
            return Result.error("一次最多只能操作100个用户");
        }
        
        String currentUserId = AuthContextUtils.getCurrentUserId();
        
        int updated = userService.batchUpdateUserStatus(userIds, 1);
        
        logger.info("批量启用用户成功: count={}, operator={}", updated, currentUserId);
        
        return Result.success(String.format("成功启用%d个用户", updated));
    }
    
    /**
     * 批量禁用用户
     */
    @PutMapping("/batch/disable")
    @RequiresPermission("user:update")
    @RateLimit(count = 10, time = 1)
    @Operation(summary = "批量禁用用户", description = "批量禁用多个用户账号")
    public Result<String> batchDisableUsers(
        @RequestBody @Valid @Parameter(description = "用户ID列表") List<String> userIds
    ) {
        
        logger.debug("批量禁用用户请求: userIds={}, operator={}", 
            userIds, AuthContextUtils.getCurrentUserId());
        
        if (userIds == null || userIds.isEmpty()) {
            return Result.error("用户ID列表不能为空");
        }
        
        if (userIds.size() > 100) {
            return Result.error("一次最多只能操作100个用户");
        }
        
        String currentUserId = AuthContextUtils.getCurrentUserId();
        
        // 检查是否包含当前用户
        if (userIds.contains(currentUserId)) {
            return Result.error("不能禁用当前登录用户");
        }
        
        int updated = userService.batchUpdateUserStatus(userIds, 0);
        
        logger.info("批量禁用用户成功: count={}, operator={}", updated, currentUserId);
        
        return Result.success(String.format("成功禁用%d个用户", updated));
    }
    
    // ==================== 用户角色管理API ====================
    
    /**
     * 获取用户的角色列表
     */
    @GetMapping("/{userId}/roles")
    @RequiresPermission("user:query")
    @Operation(summary = "获取用户角色", description = "获取指定用户的角色ID列表")
    public Result<List<String>> getUserRoles(
            @Parameter(description = "用户ID") @PathVariable String userId) {
        
        logger.debug("获取用户角色请求: userId={}", userId);
        
        List<String> roles = userService.getUserRoles(userId);
        
        logger.debug("获取用户角色成功: userId={}, roleCount={}", userId, roles.size());
        
        return Result.success("获取成功", roles);
    }
    
    /**
     * 为用户分配角色
     */
    @PostMapping("/{userId}/roles")
    @RequiresPermission("user:assign-role")
    @RateLimit(count = 20, time = 1)
    @Operation(summary = "分配用户角色", description = "为指定用户分配角色（增量分配）")
    public Result<Void> assignUserRoles(
            @Parameter(description = "用户ID") @PathVariable String userId,
            @Parameter(description = "角色ID列表") @RequestBody List<String> roleIds) {
        
        logger.info("分配用户角色请求: userId={}, roleIds={}", userId, roleIds);
        
        // 注意：operatorId在当前实现中未被使用，传递null即可
        boolean assigned = userService.assignRoles(userId, roleIds, null);
        
        if (!assigned) {
            logger.warn("分配用户角色失败: userId={}, roleIds={}", userId, roleIds);
            return Result.error("分配角色失败，请检查用户和角色是否存在");
        }
        
        logger.info("分配用户角色成功: userId={}, roleIds={}", userId, roleIds);
        
        return Result.<Void>success("角色分配成功", null);
    }
    
    /**
     * 移除用户的角色
     */
    @DeleteMapping("/{userId}/roles")
    @RequiresPermission("user:assign-role")
    @RateLimit(count = 20, time = 1)
    @Operation(summary = "移除用户角色", description = "移除指定用户的角色")
    public Result<Void> removeUserRoles(
            @Parameter(description = "用户ID") @PathVariable String userId,
            @Parameter(description = "角色ID列表") @RequestBody List<String> roleIds) {
        
        logger.info("移除用户角色请求: userId={}, roleIds={}", userId, roleIds);
        
        boolean removed = userService.removeRoles(userId, roleIds);
        
        if (!removed) {
            logger.warn("移除用户角色失败: userId={}, roleIds={}", userId, roleIds);
            return Result.error("移除角色失败，请检查用户和角色是否存在");
        }
        
        logger.info("移除用户角色成功: userId={}, roleIds={}", userId, roleIds);
        
        return Result.<Void>success("角色移除成功", null);
    }
    
    /**
     * 同步用户角色（替换式分配）
     */
    @PutMapping("/{userId}/roles")
    @RequiresPermission("user:assign-role")
    @RateLimit(count = 20, time = 1)
    @Operation(summary = "同步用户角色", description = "同步指定用户的角色（先清除所有角色再重新分配）")
    public Result<Void> syncUserRoles(
            @Parameter(description = "用户ID") @PathVariable String userId,
            @Parameter(description = "角色ID列表") @RequestBody List<String> roleIds) {
        
        logger.info("同步用户角色请求: userId={}, roleIds={}", userId, roleIds);
        
        // 注意：operatorId在当前实现中未被使用，传递null即可
        boolean synced = userService.syncRoles(userId, roleIds, null);
        
        if (!synced) {
            logger.warn("同步用户角色失败: userId={}, roleIds={}", userId, roleIds);
            return Result.error("同步角色失败，请检查用户和角色是否存在");
        }
        
        logger.info("同步用户角色成功: userId={}, roleIds={}", userId, roleIds);
        
        return Result.<Void>success("角色同步成功", null);
    }
    
    // ==================== 辅助方法 ====================
    
}
